home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / ctask22d / tskkbd.asm < prev    next >
Assembly Source File  |  1993-06-08  |  15KB  |  756 lines

  1. ;
  2. ;    --- Version 2.2 93-06-08 10:17 ---
  3. ;
  4. ;    CTask - Keyboard handler module.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic Gmbh
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;    This module traps the keyboard interrupts to allow task switching
  14. ;    on waiting for a character.
  15. ;    To avoid problems with programs that access the keyboard buffer
  16. ;    directly instead of going through INT 16, the logic has been changed
  17. ;    in version 1.2. The keyboard characters are no longer placed into
  18. ;    a pipe, instead the keyboard hardware interrupt just sets a flag
  19. ;    to signal that there might be something in the buffer. The keyboard
  20. ;    read routines wait on this flag if the original INT 16 status call
  21. ;    indicates that no key is available.
  22. ;
  23. ;    Note that there is a slight chance of this logic leading to busy
  24. ;    waiting in the original INT 16. This could happen if the process
  25. ;    is interrupted between the status check and the actual keyboard
  26. ;    fetch, and the interrupting routine snatches away the keystroke.
  27. ;    Since this is not very likely to occur, and would not be fatal
  28. ;    anyway, it would be overkill to try to avoid this.
  29. ;
  30. ;    If INT 16 is entered via CTask's t_read_key and t_wait_key,
  31. ;    the stack is not switched.
  32. ;
  33. ;    In Version 2.1, the keyboard access routines (t_read_key etc.) 
  34. ;    were moved to file 'tsksec.asm' to save code space in secondary
  35. ;    kernels. Also, the bug that the stack was always switched, contrary
  36. ;    to what the above paragraph said, was fixed.
  37. ;    The t_xxx routines now use the extended keyboard functions
  38. ;    if available. Function 5 (stuff keyboard buffer) is intercepted
  39. ;    to set the tsk_key_avail flag.
  40. ;
  41. ;    Version 2.1 adds hotkey processing to the INT 9 frontend.
  42. ;    It would be "nicer" to process hotkeys in the INT 15 scancode
  43. ;    intercept BIOS hook, but this hook is not present in older
  44. ;    XT and AT BIOSes. Version 2.2 will use the INT 15 entry if the
  45. ;    BIOS indicates that it does support it.
  46. ;
  47. ;    CAUTION: This module can only be installed in the primary kernel.
  48. ;         It is not ROMable.
  49. ;
  50.     name    tskkbd
  51. ;
  52.     include    tsk.mac
  53.     include    tskdeb.h
  54. ;
  55.     .tsk_model
  56. ;
  57.     Pubfunc    tsk_install_kbd
  58.     Pubfunc    tsk_remove_kbd
  59. ;
  60.     public    tsk_key_avail
  61. ;
  62.     Globext    yield
  63.     Globext    create_flag
  64.     Globext    delete_flag
  65.     Globext    set_flag
  66.     Globext    clear_flag
  67.     Globext    wait_flag_set
  68.     extrn    sched_int: far
  69.     Locext    tsk_switch_stack
  70.     Locext    tsk_old_stack
  71.     Locext    tsk_timer_action
  72.     Locext    tsk_dequeue
  73.     Locext    tsk_putqueue
  74. ;
  75.     IF    DEBUG AND DEB_FLASHERS
  76.     Locext    tsk_inccdis
  77.     extrn    tsk_debflash: word
  78.     ENDIF
  79. ;
  80.     extrn    tsk_glob_rec: byte
  81. ;
  82. inta00        =    20h    ; 8259 int controller base
  83. eoi        =    20h    ; unspecific EOI
  84. ;
  85. keyb_data    =    60h    ; keyboard data port
  86. keyb_ctl    =    61h    ; keyboard control (PC/XT only)
  87. ;
  88. intseg    segment at 0
  89.         org    09h*4
  90. hwdoff        dw    ?    ; keyboard hardware interrupt
  91. hwdseg        dw    ?
  92.         org    15h*4
  93. int15off     dw    ?    ; system services interrupt
  94. int15seg     dw    ?
  95.         org    16h*4
  96. kbdoff        dw    ?    ; keyboard I/O interrupt
  97. kbdseg        dw    ?
  98. ;
  99. intseg    ends
  100. ;
  101. biosdata    segment at 40h
  102.         org    17h
  103. keyb_flags_1    db    ?
  104. keyb_flags_2    db    ?
  105.         org    96h
  106. keyb_flags_3    db    ?
  107. ;
  108. biosdata    ends
  109. ;
  110. ;----------------------------------------------------------------------------
  111. ;
  112. ;    Variables
  113. ;
  114.     .tsk_data
  115. ;
  116.     IF    TSK_NAMEPAR
  117. kbd_name    db    "KEYAVAIL",0
  118.     ENDIF
  119. ;
  120. tsk_key_avail    flag <>
  121. ;
  122.     .tsk_edata
  123.     .tsk_code
  124. ;
  125. ;
  126. ;    Original Interrupt-Entries
  127. ;
  128. savhwd        label    dword        ; original hardware int entry
  129. savhwdoff    dw    ?
  130. savhwdseg    dw    ?
  131. ;
  132. savkbd        label    dword        ; original keyboard I/O entry
  133. savkbdoff    dw    ?
  134. savkbdseg    dw    ?
  135. ;
  136. savint15    label    dword        ; original system services entry
  137. savint15off    dw    ?
  138. savint15seg    dw    ?
  139. ;
  140. ext_keyboard    db    0        ; extended keyboard BIOS present
  141. kb_intercept    db    0        ; keyboard intercept is called
  142. sched_pending    db    0        ; scheduler call is pending
  143. ;
  144. ;---------------------------------------------------------------------------
  145. ;
  146. ;    check_hotkey checks the hotkey queue passed in ES:BX for
  147. ;    a match. If there is a match, the associated action is
  148. ;    performed (via tsk_timer_action, since hotkey elements are
  149. ;    essentially timer elements).
  150. ;
  151. ;    Returns Carry set if no match, Carry clear on match.
  152. ;
  153.     IF    HOTKEYS
  154. ;
  155. @check_hotkey    proc    near
  156. ;
  157.     push    ds
  158. ;
  159.     mov    cx,SEG biosdata
  160.     mov    ds,cx
  161.     assume    ds:biosdata        ; for checking the flags
  162. ;
  163.     cmp    es:telem.scancode[bx],0
  164.     je    no_scancomp
  165. ;
  166. checkhotloop:
  167.     cmp    es:telem.scancode[bx],al
  168.     jne    hot_next            ; no more checks on mismatch
  169. ;
  170. no_scancomp:
  171.     cmp    es:telem.kbflags1.hf_mask[bx],0        ; check flag 1?
  172.     je    no_flcomp1                ; jump if not
  173. ;
  174.     mov    ah,keyb_flags_1
  175.     and    ah,es:telem.kbflags1.hf_mask[bx]
  176.     cmp    ah,es:telem.kbflags1.hf_value[bx]
  177.     jne    hot_next            ; no more checks on mismatch
  178. ;
  179. no_flcomp1:
  180.     cmp    es:telem.kbflags2.hf_mask[bx],0        ; check flag 2?
  181.     je    no_flcomp2                       ; jump if not
  182. ;
  183.     mov    ah,keyb_flags_2
  184.     and    ah,es:telem.kbflags2.hf_mask[bx]
  185.     cmp    ah,es:telem.kbflags2.hf_value[bx]
  186.     jne    hot_next            ; no more checks on mismatch
  187. ;
  188. no_flcomp2:
  189.     cmp    es:telem.kbflags3.hf_mask[bx],0        ; check flag 3?
  190.     je    do_hotkey                       ; match if not
  191. ;
  192.     mov    ah,keyb_flags_3
  193.     and    ah,es:telem.kbflags3.hf_mask[bx]
  194.     cmp    ah,es:telem.kbflags3.hf_value[bx]
  195.     je    do_hotkey            ; match
  196. ;
  197. hot_next:
  198.     les    bx,es:tlink.q_next[bx]        ; next in queue
  199.     test    es:q_kind[bx],Q_HEAD        ; queue end?
  200.     jnz    no_hotkey
  201.     cmp    es:telem.scancode[bx],0
  202.     je    no_scancomp
  203.     jmp    checkhotloop
  204. ;
  205. no_hotkey:
  206.     sti
  207.     pop    ds
  208.     assume    ds:@CTASK_DATA
  209.     stc
  210.     ret
  211. ;
  212. ;    Execute hotkey action. First, remove from queue to allow
  213. ;    enable/disable/delete calls in the hotkey action.
  214. ;
  215. do_hotkey:
  216.     pop    ds
  217.     cli
  218.     or    es:tflags[bx],TFLAG_BUSY    ; mark busy
  219.     push    si
  220.     push    es
  221.     push    bx
  222.     callp    tsk_dequeue,<<es,bx>>        ; remove
  223.     sti
  224.     pop    bx
  225.     pop    es
  226. ;
  227.     push    es
  228.     push    bx
  229.     callp    tsk_timer_action,<<es,bx>>
  230.     pop    bx
  231.     pop    es
  232.     pop    si
  233. ;
  234. ;    If continued hotkey, re-enqueue.
  235. ;
  236.     cli
  237.     test    es:tflags[bx],TFLAG_UNQUEUE OR TFLAG_REMOVE
  238.     jnz    no_enque
  239.     test    es:tflags[bx],TFLAG_ENQUEUE OR TFLAG_REPEAT
  240.     jz    no_enque
  241.     push    es
  242.     push    bx
  243.     callp    tsk_putqueue,<<ds,si>,<es,bx>>
  244.     pop    bx
  245.     pop    es
  246. ;
  247. no_enque:
  248.     and    es:tflags[bx],NOT (TFLAG_BUSY OR TFLAG_UNQUEUE OR TFLAG_ENQUEUE)
  249.     sti
  250. ;     carry is now clear
  251.     ret
  252. ;
  253. @check_hotkey    endp
  254. ;
  255.     ENDIF
  256. ;
  257. ;---------------------------------------------------------------------------
  258. ;
  259. ;    void tsk_install_kbd (void)
  260. ;
  261. ;        Install keyboard handler
  262. ;
  263. Localfunc tsk_install_kbd
  264. ;
  265.     IFDEF    LOAD_DS
  266.     push    ds
  267.     mov    ax,@CTASK_DATA
  268.     mov    ds,ax
  269.     ENDIF
  270. ;
  271. ;    Check for extended keyboard BIOS functions. Since there is no
  272. ;    error return when executing the functions in non-extended BIOS
  273. ;    versions, we have to do a little guesswork.
  274. ;
  275.     mov    cs:ext_keyboard,0
  276. ;
  277.     push    ds
  278.     mov    ax,40h
  279.     mov    ds,ax
  280.     assume    ds:biosdata
  281. ;
  282.     mov    ax,11ffh    ; this certainly is no valid key
  283.     int    16h        ; get extended status
  284.     cmp    ax,11ffh    ; has the value changed?
  285.     je    not_extended    ; if not, it's surely not extended.
  286.     cli
  287.     mov    bl,keyb_flags_1
  288.     mov    ah,12h
  289.     int    16h
  290.     cmp    bl,al
  291.     jne    not_extended
  292.     not    al
  293.     mov    keyb_flags_1,al
  294.     mov    ah,12h
  295.     int    16h
  296.     mov    keyb_flags_1,bl
  297.     sti
  298.     not    al
  299.     cmp    bl,al
  300.     jne    not_extended
  301. ;
  302. ;    An extended keyboard BIOS is present. This BIOS likely also supports
  303. ;    the INT 15 intercept hook, so check for it with the "return config
  304. ;    parameters" call.
  305. ;
  306.     inc    cs:ext_keyboard
  307.     IF    HOTKEYS
  308.     mov    ah,0c0h
  309.     int    15h
  310.     jc    not_extended
  311.     or    ah,ah
  312.     jnz    not_extended
  313.     cmp    word ptr es:[bx],8
  314.     jb    not_extended
  315.     test    byte ptr es:5[bx],10h    ; keyboard intercept present
  316.     jz    not_extended
  317.     inc    cs:kb_intercept
  318.     ENDIF
  319. ;
  320. not_extended:
  321.     sti
  322.     pop    ds
  323. ;
  324.     assume    ds:@CTASK_DATA
  325. ;
  326.     IF    TSK_NAMEPAR
  327.     callp    create_flag,<<ds,#tsk_key_avail>,<ds,#kbd_name>>
  328.     ELSE
  329.     callp    create_flag,<<ds,#tsk_key_avail>>
  330.     ENDIF
  331. ;
  332. ;    Save old interrupt vectors
  333. ;
  334.         push    es
  335.     xor    ax,ax
  336.     mov    es,ax
  337. ;
  338.         assume  es:intseg
  339. ;
  340.     mov    ax,kbdoff
  341.     mov    savkbdoff,ax
  342.     mov    ax,kbdseg
  343.     mov    savkbdseg,ax
  344. ;
  345.     mov    ax,hwdoff
  346.     mov    savhwdoff,ax
  347.     mov    ax,hwdseg
  348.     mov    savhwdseg,ax
  349. ;
  350.     IF    HOTKEYS
  351.     cmp    cs:kb_intercept,0
  352.     je    enter_new
  353.     mov    ax,int15off
  354.     mov    savint15off,ax
  355.     mov    ax,int15seg
  356.     mov    savint15seg,ax
  357.     cli
  358.     mov    int15off,offset @intercept
  359.     mov    int15seg,cs
  360.     ENDIF
  361. ;
  362. ;    Enter new Interrupt-Entries
  363. ;
  364. enter_new:
  365.     cli
  366.     mov    kbdoff,offset @kbdentry
  367.     mov    kbdseg,cs
  368.     mov    hwdoff,offset @hwdentry
  369.     mov    hwdseg,cs
  370.     sti
  371.         pop     es
  372. ;
  373.     IFDEF    LOAD_DS
  374.     pop    ds
  375.     ENDIF
  376.     ret
  377. ;
  378.     assume    es:nothing
  379. ;
  380. tsk_install_kbd    endp
  381. ;
  382. ;
  383. ;    void tsk_remove_kbd (void)
  384. ;
  385. ;        Un-install keyboard handler
  386. ;
  387. Localfunc tsk_remove_kbd
  388. ;
  389.     IFDEF    LOAD_DS
  390.     push    ds
  391.     mov    ax,@CTASK_DATA
  392.     mov    ds,ax
  393.     ENDIF
  394. ;
  395.         push    es
  396.     xor    ax,ax
  397.     mov    es,ax
  398. ;
  399.         assume  es:intseg
  400. ;
  401. ;    Restore interrupt entries
  402. ;
  403.     cli
  404. ;
  405.     mov    ax,savkbdoff
  406.     mov    kbdoff,ax
  407.     mov    ax,savkbdseg
  408.     mov    kbdseg,ax
  409. ;
  410.     mov    ax,savhwdoff
  411.     mov    hwdoff,ax
  412.     mov    ax,savhwdseg
  413.     mov    hwdseg,ax
  414. ;
  415.     IF    HOTKEYS
  416.     cmp    cs:kb_intercept,0
  417.     je    rest_ready
  418.     mov    ax,savint15off
  419.     mov    int15off,ax
  420.     mov    ax,savint15seg
  421.     mov    int15seg,ax
  422.     ENDIF
  423. ;
  424. rest_ready:
  425.     sti
  426. ;
  427.         pop     es
  428. ;
  429. ;    Delete the keyboard available flag
  430. ;
  431.     callp    delete_flag,<<ds,#tsk_key_avail>>
  432. ;
  433.     IFDEF    LOAD_DS
  434.     pop    ds
  435.     ENDIF
  436.     ret
  437. ;
  438.     assume    es:nothing
  439. ;
  440. tsk_remove_kbd    endp
  441. ;
  442. ;
  443. ;
  444. ;---------------------------------------------------------------------------
  445. ;---------------------------------------------------------------------------
  446. ;
  447. ;    INT 9 - Keyboard hardware interrupt
  448. ;
  449. ;    Version 2.1 adds hotkey processing.
  450. ;
  451. @hwdentry    proc    far
  452. ;
  453.         call    tsk_switch_stack
  454.     IF    DEBUG AND DEB_FLASHERS
  455.     cmp    tsk_debflash,0
  456.     je    debdd0
  457.     mov    ax,DEBP_CNTKEYBD
  458.     call    tsk_inccdis
  459. debdd0:
  460.     ENDIF
  461. ;
  462. ;    Check the scancode hotkey queue.
  463. ;    Two queues are maintained for hotkeys, one for hotkey elements
  464. ;    with nonzero scancode, and one for zero scancode elements.
  465. ;    If there is no scancode, the hotkey is a shift-key combination,
  466. ;    which can only be checked *after* chaining to the old INT 9.
  467. ;    Hotkeys with scancode have to be checked *before* chaining,
  468. ;    so the scancode can be removed on a match.
  469. ;    If the BIOS supports keyboard intercept, this part is skipped.
  470. ;
  471.     IF    HOTKEYS
  472.     cmp    cs:kb_intercept,0
  473.     jne    no_firstcheck
  474.     lea    si,tsk_glob_rec.hotkey_scan.q_first
  475.     les    bx,dword ptr [si]
  476.     test    es:q_kind[bx],Q_HEAD    ; queue empty?
  477.     jnz    no_firstcheck        ; then don't read key
  478.     in    al,keyb_data
  479.     call    @check_hotkey
  480.     jnc    hotkey_found        ; remove scancode on match
  481. ;
  482. no_firstcheck:
  483.     ENDIF
  484. ;
  485.     pushf
  486.         cli
  487.     call    cs:savhwd        ; let original handler process key
  488. ;
  489.     callp    set_flag,<<ds,#tsk_key_avail>>
  490. ;
  491. ;    check no-scancode hotkeys
  492. ;
  493.     IF    HOTKEYS
  494.     lea    si,tsk_glob_rec.hotkey_noscan.q_first
  495.     les    bx,dword ptr [si]
  496.     test    es:q_kind[bx],Q_HEAD    ; queue empty?
  497.     jnz    no_nshot        ; don't check if yes
  498.     call    @check_hotkey
  499.     jnc    immed_sched        ; schedule on hotkey match
  500. ;
  501. no_nshot:
  502.     cmp    cs:sched_pending,0
  503.     jne    immed_sched
  504.     ENDIF
  505. ;
  506.     iret
  507. ;
  508.     IF    HOTKEYS
  509. hotkey_found:
  510. ;
  511. ;    Acknowledge keyboard, so hotkey disappears.
  512. ;
  513.     cli
  514.     in    al,keyb_ctl
  515.     mov    ah,al
  516.     or    al,80h
  517.     out    keyb_ctl,al
  518.     xchg    ah,al
  519.     out    keyb_ctl,al
  520. ;
  521.     mov    al,eoi
  522.     out    inta00,al
  523.     sti
  524. ;
  525. ;    on a hotkey match, we schedule immediately.
  526. ;
  527. immed_sched:
  528.     cli
  529.     mov    cs:sched_pending,0
  530.     mov    al,0bh            ; access int control reg
  531.     out    inta00,al
  532.     in    al,inta00        ; ints pending?
  533.     or    al,al
  534.     jnz    no_immed        ; don't schedule if other ints active
  535.     sti
  536.     call    tsk_old_stack
  537.     jmp    sched_int
  538. ;
  539. no_immed:
  540.     iret
  541.     ENDIF
  542. ;
  543. @hwdentry    endp
  544. ;
  545. ;
  546.     IF    HOTKEYS
  547. ;
  548. @intercept    proc    far
  549. ;
  550.     cmp    ah,4fh
  551.     je    do_intercept
  552.     jmp    cs:savint15
  553. ;
  554. do_intercept:
  555.     pushf
  556.     sti
  557.     cld
  558.     push    ds
  559.     push    es
  560.     push    si
  561.     push    di
  562.     push    bx
  563.     push    ax
  564.     mov    si,@CTASK_DATA
  565.     mov    ds,si
  566. ;
  567.     lea    si,tsk_glob_rec.hotkey_scan.q_first
  568.     les    bx,dword ptr [si]
  569.     test    es:q_kind[bx],Q_HEAD    ; queue empty?
  570.     jz    inter_check
  571.     stc
  572.     jmp    short inter_ret
  573. ;
  574. inter_check:
  575.     push    cx
  576.     push    dx
  577.     call    @check_hotkey
  578.     pop    dx
  579.     pop    cx
  580. ;
  581. inter_ret:
  582.     pop    ax
  583.     pop    bx
  584.     pop    di
  585.     pop    si
  586.     pop    es
  587.     pop    ds
  588.     jc    inter_chain
  589.     popf
  590.     mov    cs:sched_pending,1
  591.     clc
  592.     ret    2
  593. ;
  594. inter_chain:
  595.     popf
  596.     jmp    cs:savint15
  597. ;
  598. @intercept    endp
  599. ;
  600.     ENDIF
  601. ;
  602. ;---------------------------------------------------------------------------
  603. ;---------------------------------------------------------------------------
  604. ;
  605. ;    INT 16 - Keyboard I/O
  606. ;
  607. @kbdentry    proc    far
  608. ;
  609.         pushf
  610.     sti
  611.     or    ah,ah
  612.     jnz    kbdent1
  613.     jmp    kbd_read
  614. kbdent1:
  615.     cmp    ah,1
  616.     je    kbd_poll
  617.     cmp    ah,11h
  618.     je    kbd_poll
  619.     cmp    ah,10h
  620.     jz    kbd_read_ext    ; extended read
  621.     cmp    ah,05h
  622.     jz    kbd_stuff    ; stuff char in key buffer
  623.     cmp    ax,4012h
  624.     jz    kbd_readns
  625.     cmp    ax,4112h
  626.     jz    kbd_readns
  627.     cmp    ax,4212h
  628.     jz    kbd_keyhit
  629. ;
  630. kbd_pass:
  631.         popf
  632.     jmp    cs:savkbd    ; pass on functions != 0
  633. ;
  634. ;    The "4212" code is used by t_keyhit. It will execute function
  635. ;    1 or 11h depending on ext_keyboard.
  636. ;
  637. kbd_keyhit:
  638.     mov    ah,1
  639.     cmp    cs:ext_keyboard,0
  640.     je    kbd_pass
  641.     mov    ah,11h
  642.     jmp    kbd_pass
  643. ;
  644. ;    The "4012" and "4112" codes are used by t_wait_key and t_read_key.
  645. ;    The t_wait_key code 4012 uses the timeout supplied in CX:DX.
  646. ;    The t_read_key code 4112 uses an endless timeout (0L).
  647. ;
  648. kbd_readns:
  649.     popf            ;2.1a
  650.     sti            ;2.1a
  651.     push    ds        ;2.1a
  652.     mov    bx,@CTASK_DATA    ;2.1a
  653.     mov    ds,bx        ;2.1a
  654.     mov    bx,8001h
  655.     cmp    cs:ext_keyboard,0
  656.     je    readns1
  657.     mov    bx,9011h
  658. readns1:
  659. ;2.1a    popf
  660.     cmp    ah,40h
  661.     jne    kbd_read2
  662.     jmp    short kbr_loop
  663. ;
  664. kbd_stuff:
  665.         popf
  666.     call    cs:savkbd
  667.     call    tsk_switch_stack
  668.     mov    ax,entry_flags[bp]
  669.     mov    caller_flags[bp],ax
  670.     callp    set_flag,<<ds,#tsk_key_avail>>
  671.     iret
  672. ;
  673. kbd_read_ext:
  674.     cmp    cs:ext_keyboard,0
  675.     je    kbd_pass        ; pass on if no extended kbd
  676.     mov    al,11h
  677.     jmp    short kbd_read1
  678. ;
  679. ;
  680. kbd_poll:
  681.     cli
  682.     call    cs:savkbd
  683.     jnz    kbd_poll_end
  684. ;
  685.     push    ax
  686.     push    bx
  687.     push    ds
  688.     push    es
  689.     mov    ax,@CTASK_DATA
  690.     mov    ds,ax
  691.     callp    yield
  692.     pop    es
  693.     pop    ds
  694.     pop    bx
  695.     pop    ax
  696.     cmp    ax,ax
  697. ;
  698. kbd_poll_end:
  699.     retf    2
  700. ;
  701. kbd_read:
  702.     mov    al,1
  703. kbd_read1:
  704.         popf
  705.     call    tsk_switch_stack
  706.     mov    bx,ax
  707. kbd_read2:
  708.     xor    cx,cx
  709.     mov    dx,cx
  710. ;
  711. kbr_loop:
  712.     push    bx
  713.     push    cx
  714.     push    dx
  715.     callp    clear_flag,<<ds,#tsk_key_avail>>
  716.     pop    dx
  717.     pop    cx
  718.     pop    bx
  719.     mov    ah,bl
  720.     pushf
  721.     cli
  722.     call    cs:savkbd
  723.     jnz    kbr_get_key
  724.     push    bx
  725.     push    cx
  726.     push    dx
  727.     callp    wait_flag_set,<<ds,#tsk_key_avail>,<cx,dx>>
  728.     pop    dx
  729.     pop    cx
  730.     pop    bx
  731.     or    ax,ax
  732.     jz    kbr_loop
  733.     mov    ax,-1
  734.     jmp    short kbr_retn
  735. ;
  736. kbr_get_key:
  737.     mov    ah,bh
  738.     and    ah,7fh
  739.     pushf
  740.     cli
  741.     call    cs:savkbd
  742. kbr_retn:
  743.     test    bh,80h
  744.     jnz    kbr_retns
  745.     mov    save_ax[bp],ax
  746.     iret            ;2.1a
  747. kbr_retns:
  748.     pop    ds        ;2.1a
  749.     iret
  750. ;
  751. @kbdentry    endp
  752. ;
  753.     .tsk_ecode
  754.     end
  755.  
  756.